package com.algo.core.netty;

import com.algo.core.processor.HttpRequestQueue;
import com.algo.core.LifeCycle;
import com.algo.core.RapidSeverConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpServerCodec;
import org.apache.log4j.Logger;

/**
 * 网关服务端，在这里监听指定端口，对外服务
 */
public class HttpNettyServer implements LifeCycle {

    private final static Logger logger  = Logger.getLogger(HttpNettyServer.class);

    // 默认端口8888
    private int port = 8888;

    // 服务端配置信息
    private RapidSeverConfig rapidSeverConfig;

    private HttpRequestQueue httpRequestQueue;

    private EventLoopGroup bossLoopGroup;

    private EventLoopGroup workLoopGroup;

    private ServerBootstrap serverBootstrap;

    public HttpNettyServer(RapidSeverConfig rapidSeverConfig, HttpRequestQueue httpRequestQueue) {
        this.rapidSeverConfig = rapidSeverConfig;
        this.httpRequestQueue = httpRequestQueue;
        initilize();
    }

    /**
     * 初始化
     */
    public void initilize() {
        if (rapidSeverConfig.getServerPort() > 0 && rapidSeverConfig.getServerPort() < 65535) {
            this.port = rapidSeverConfig.getServerPort();
        }

        serverBootstrap = new ServerBootstrap();
        if (useEpoll()) {
            bossLoopGroup = new EpollEventLoopGroup(rapidSeverConfig.getBossLoopGroupCount());
            workLoopGroup = new EpollEventLoopGroup(rapidSeverConfig.getWorkLoopGroupCount());
        } else {
            bossLoopGroup = new NioEventLoopGroup(rapidSeverConfig.getBossLoopGroupCount());
            workLoopGroup = new NioEventLoopGroup(rapidSeverConfig.getWorkLoopGroupCount());
        }
    }

    /**
     * 开启打开nettyServer
     */
    public void start() {
        serverBootstrap
                .group(bossLoopGroup, workLoopGroup)
                .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .childHandler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ch.pipeline()
                                .addLast(new HttpServerCodec())
                                .addLast(new HttpObjectAggregator(1024 * 512)) // 消息聚合
//                                .addLast(new LoggerChannelInboundHandler())
                                .addLast(new ServerChannelHandler(httpRequestQueue));
                    }
                });

        try {
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            logger.info("server run success, listen port : " + port);
        } catch (Exception e) {
            logger.info("server run error, error is " + e);
        }
    }

    /**
     * 关闭资源，比如eventLoopGroup
     */
    public void shutdown() {
        bossLoopGroup.shutdownGracefully();
        workLoopGroup.shutdownGracefully();
    }

    /**
     * 是否支持 epoll
     * @return
     */
    private boolean useEpoll() {
        return rapidSeverConfig.isUseEpoll() && System.getProperties() != null
                && (System.getProperties().getProperty("os.name").toLowerCase().contains("linux"));
    }

}
